Mapas en acción. Calentando motores

Author

Tomás Bustos

Mapas & elecciones: visualización de información geográfica con R en Ciencias Sociales

El objetivo del curso es adquirir herramientas para la visualización de información geográfica utilizando R en el ámbito de las Ciencias Sociales. Se utilizarán datos electorales como un ejemplo concreto y cercano, un hilo temático que le dará estructura, coherencia e integridad a los encuentros. Habrá contenidos de tres tipos: manejo de datos, herramientas de visualización y un ejemplo concreto donde lo anterior esté aplicado. La idea es ir avanzando de manera iterativa, pasando en todas los encuentros por los tres tipos de contenidos mencionados antes e ir complejizando su utilziación a medida que avanzan los encuentros.

Como herramienta didáctica, cada encuentro tendrá una pregunta que nos guíe. Es importante para evitar perdernos en el mar de información disponible. Enfocar los esfuerzos nos va a ayudar a buscar mejor qué función necesitamos para responder nuestra pregunta y además valoriza uno de los elementos más importantes que tienen para aportar las Ciencias Sociales al mundo de datos: hacer preguntas interesantes.

1. Calentando motores

La idea de este encuentro es repasar manejo de datos con tidyverse, conocer objetos geográficos mínimos con sf y hacer una pequeña introducción a visualización con ggplot.

Librerías necesarias: tidyverse, sf.

1.1. Antes de arrancar: conociendo los utensilios

Un breve y necesario paréntesis de definiciones de los elementos con los que vamos a estar trabajando.

  • Script: secuencia de comandos. Nuestros scripts estarán escritos en R.

  • Rstudio: plataforma que usaremos para administrar los archivos necesarios para trabajar con R.

  • Proyecto de Rstudio: es una forma de agrupar los distintos scripts y archivos que utilicemos en un sólo lugar. También nos facilita trabajar con directorios o guardar ciertas configuraciones del entorno.

  • Documento de R (.r): archivo con instrucciones escritas en R.

  • Documento de RMarkdown (.rmd): archivo que permite combinar instrucciones escritas en R con distintos formatos de texto. Se utiliza para escribir informes fáciles para leer y cómodos para trabajar.

  • Quarto document (.qmd): Símil al anterior, pero permite distintos lenguajes. Es el que está presente en la mayor parte de este curso.

  • Función: conjunto de instrucciones empaquetados para usar con mayor comodidad.

  • Paquete/Librerías: conjunto de funciones, en general, con el objetivo de trabajar en un rubro en particular o con cierto tipo de datos.

1.2. Pregunta-problema

Por ser el primer encuentro vamos a empezar por una pregunta sencilla. ¿Cómo fue el porcentaje de votos de La Libertad Avanza en las provincias argentinas en las elecciones presidenciales generales de 2023?

1.3. Introducción a toda marcha

Lo primero y principal es cargar las librerías que vamos a utilizar para responder a nuestra pregunta-problema. Aquí le damos la bienvenida a tidyverse: un conjunto de paquetes quetienen una manera similar de escribirse y utilizarse, facilitando el trabajo conjunto de las distintas librerías. La primera vez que se utiliza una librería, hay que descargarla con la función install.packages().

Code
#install.packages("tidyverse") # instalamos el conjunto de librerías que componen la colección tidyverse
#install.packages("sf") # instalamos la librería que usaremos para operaciones con información geográfica

Una vez instalados los paquetes se cargan en la instancia de trabajo que estamos utilizando.

Code
library(tidyverse)
library(sf)

Luego, tenemos que cargar los datos que vamos a utilizar. La función dependerá del tipo de archivo que tengamos que cargar. Los tipos de archivos más comunes son .csv y .xlsx. Los datos están descargados de la plataforma Data CP. Si hay problemas con la ruta, pueden saber dónde está ubicado R con la función getwd().

Cuando utilizamos R vamos a estar utilizando objetos. El operador <- se utiliza para asignar el resultado de una función a un objeto y se puede crear con botón alt + botón -. Los objetos pertenecen a una clase, lo que implica que se permiten ciertas operaciones y se restringen otras. Por ejemplo, a los números se les puede aplicar operaciones aritméticas, a las tablas se les puede consultar sus filas-columnas y a las cadenas de texto se las puede pasar a mayúsculas.

Code
class(data)
[1] "tbl_df"     "tbl"        "data.frame"

A los archivos del tipo data.frame podemos aplicarle distintas funciones para hacer una exploración rápida de qué hay dentro. dim devuelve filas y columnas:

Code
dim(data)
[1] 192   8

glipmse() devuelve nombres de columnas, tipos de datos, valores de ejemplo:

Code
glimpse(data)
Rows: 192
Columns: 8
$ id            <chr> "BUENOS AIRES", "CATAMARCA", "CHACO", "CHUBUT", "CIUDAD …
$ Elecciones    <chr> "GENERALES 2023", "GENERALES 2023", "GENERALES 2023", "G…
$ Partido       <chr> "BLANCO", "BLANCO", "BLANCO", "BLANCO", "BLANCO", "BLANC…
$ Porcentaje    <chr> "2.64", "5.16", "1.1", "1.27", "1.69", "0.77", "1.1", "4…
$ Votos         <chr> "269648", "12804", "7960", "4502", "32311", "17852", "78…
$ Participacion <chr> "77.71", "72.81", "72.45", "74.54", "75.65", "76.19", "7…
$ Electores     <chr> "13124435", "340606", "1000094", "474701", "2526676", "3…
$ Votantes      <chr> "10199399", "247986", "724566", "353825", "1911431", "23…

Para seleccionar filas que nos interesan, según algún valor, podemos utilizar la función filter().

Code
data %>% 
  filter(Partido=="LA LIBERTAD AVANZA" & Porcentaje > 40)
# A tibble: 4 × 8
  id       Elecciones  Partido Porcentaje Votos Participacion Electores Votantes
  <chr>    <chr>       <chr>   <chr>      <chr> <chr>         <chr>     <chr>   
1 MENDOZA  GENERALES … LA LIB… 42.36      4693… 76.45         1494888   1142804 
2 MISIONES GENERALES … LA LIB… 42.13      3056… 75.89         989204    750671  
3 SALTA    GENERALES … LA LIB… 40.4       3091… 71.66         1091792   782342  
4 SAN LUIS GENERALES … LA LIB… 43.37      1382… 77.99         421037    328355  

Con el operador pipe (%>%) se concatenan las distintas funciones. Si en cambio queremos seleccionar algunas columnas, la función select() es la indicada:

Code
data %>% 
  filter(Partido=="LA LIBERTAD AVANZA") %>% 
  select(id, Porcentaje)
# A tibble: 24 × 2
   id                              Porcentaje
   <chr>                           <chr>     
 1 BUENOS AIRES                    25.72     
 2 CATAMARCA                       32.04     
 3 CHACO                           27.77     
 4 CHUBUT                          35.02     
 5 CIUDAD AUTONOMA DE BUENOS AIRES 19.85     
 6 CORDOBA                         33.55     
 7 CORRIENTES                      26.89     
 8 ENTRE RIOS                      29.75     
 9 FORMOSA                         29.04     
10 JUJUY                           37.39     
# ℹ 14 more rows

Limpiar y transformar una base de datos es un proceso creativo que implica adaptar las variables según el uso que se le va a dar. Se dice creativo porque, si bien hay ciertas funciones y procesos frecuentes, varía mucho según cada proyecto y origen de la base. mutate() es una de las funciones más importantes para este momento.

Code
data %>% 
  mutate(provincia_minusc = str_to_lower(id),
         participacion_v2 = as.numeric(Votantes) / as.numeric(Electores) * 100) %>% 
  select(id, provincia_minusc, Participacion, participacion_v2)
# A tibble: 192 × 4
   id                            provincia_minusc Participacion participacion_v2
   <chr>                         <chr>            <chr>                    <dbl>
 1 BUENOS AIRES                  buenos aires     77.71                     77.7
 2 CATAMARCA                     catamarca        72.81                     72.8
 3 CHACO                         chaco            72.45                     72.4
 4 CHUBUT                        chubut           74.54                     74.5
 5 CIUDAD AUTONOMA DE BUENOS AI… ciudad autonoma… 75.65                     75.7
 6 CORDOBA                       cordoba          76.19                     76.2
 7 CORRIENTES                    corrientes       76.8                      76.8
 8 ENTRE RIOS                    entre rios       76.8                      76.8
 9 FORMOSA                       formosa          75.61                     75.6
10 JUJUY                         jujuy            78.35                     78.4
# ℹ 182 more rows

A veces es necesario hacer cálculos de agrupamiento en nuestras tablas. Las funciones group_by() y summarise() pueden funcionar. Por ejemplo, calculemos el promedio de cada partido en las distintas provincias:

Code
data %>% 
  select(Partido, Porcentaje) %>% 
  mutate(Porcentaje = as.numeric(Porcentaje)) %>% 
  group_by(Partido) %>% 
  summarise(mean = mean(Porcentaje)) %>% 
  arrange(desc(mean)) %>% 
  mutate(mean = round(mean, 2))
# A tibble: 8 × 2
  Partido                                         mean
  <chr>                                          <dbl>
1 UNION POR LA PATRIA                            36.8 
2 LA LIBERTAD AVANZA                             33.4 
3 JUNTOS POR EL CAMBIO                           20.8 
4 HACEMOS POR NUESTRO PAIS                        6.55
5 FRENTE DE IZQUIERDA Y DE TRABAJADORES - UNIDAD  2.37
6 BLANCO                                          2.04
7 NULO                                            0.99
8 IMPUGNADO                                       0.11

Tip: mantené los nombres de variables simples, sin espacios y con mayúsculas/minúsculas consistentes.

1.4. Formatos

La mayor particularidad de los resultados electorales es tener formato long (largo). En el formato long, cada fila de la tabla representa una observación única para una combinación específica de variables. Es útil para trabajar con datos que necesitan ser agrupados o resumidos fácilmente. Cada variable está dividida en dos columnas: una para el nombre de la variable y otra para su valor. El formato alternativo es wide, donde cada fila representa una observación única y cada columna representa una variable diferente. Es útil cuando se necesita acceder rápidamente a las variables individuales sin necesidad de realizar transformaciones adicionales.

formatos de tabla

Quizás sea más cómodo alternar entre formato long y wide. Para aquellos casos, pivot_longer() y pivot_wider() nos van a servir.

Las bases electorales suelen venir en formato long. Para la lectura, suele ser más cómodo el formato wide.

Code
data_wider <- data %>%
  select(id, Partido, Porcentaje) %>% 
  pivot_wider(names_from=Partido, values_from=Porcentaje)
data_wider
# A tibble: 24 × 9
   id             BLANCO FRENTE DE IZQUIERDA …¹ HACEMOS POR NUESTRO …² IMPUGNADO
   <chr>          <chr>  <chr>                  <chr>                  <chr>    
 1 BUENOS AIRES   2.64   3.58                   3.73                   0.13     
 2 CATAMARCA      5.16   1.57                   6.43                   0.26     
 3 CHACO          1.1    0.77                   3.63                   0.16     
 4 CHUBUT         1.27   4.4                    7.73                   0.11     
 5 CIUDAD AUTONO… 1.69   3.55                   3.09                   0.12     
 6 CORDOBA        0.77   1.39                   29.01                  0.03     
 7 CORRIENTES     1.1    1.05                   2.74                   0.12     
 8 ENTRE RIOS     4.25   1.53                   5.37                   0.16     
 9 FORMOSA        1.28   0.77                   2.46                   0.07     
10 JUJUY          1.35   3.54                   6.81                   0.07     
# ℹ 14 more rows
# ℹ abbreviated names: ¹​`FRENTE DE IZQUIERDA Y DE TRABAJADORES - UNIDAD`,
#   ²​`HACEMOS POR NUESTRO PAIS`
# ℹ 4 more variables: `JUNTOS POR EL CAMBIO` <chr>, `LA LIBERTAD AVANZA` <chr>,
#   NULO <chr>, `UNION POR LA PATRIA` <chr>

Si quisiéramos volver al formato anterior:

Code
data_wider %>% 
  pivot_longer(!id, values_to="valor")
# A tibble: 192 × 3
   id           name                                           valor
   <chr>        <chr>                                          <chr>
 1 BUENOS AIRES BLANCO                                         2.64 
 2 BUENOS AIRES FRENTE DE IZQUIERDA Y DE TRABAJADORES - UNIDAD 3.58 
 3 BUENOS AIRES HACEMOS POR NUESTRO PAIS                       3.73 
 4 BUENOS AIRES IMPUGNADO                                      0.13 
 5 BUENOS AIRES JUNTOS POR EL CAMBIO                           24.1 
 6 BUENOS AIRES LA LIBERTAD AVANZA                             25.72
 7 BUENOS AIRES NULO                                           0.63 
 8 BUENOS AIRES UNION POR LA PATRIA                            42.88
 9 CATAMARCA    BLANCO                                         5.16 
10 CATAMARCA    FRENTE DE IZQUIERDA Y DE TRABAJADORES - UNIDAD 1.57 
# ℹ 182 more rows

1.5. Visualización

En este apartado nos enfocaremos en entender por qué visualizar datos y cómo construirlos utilizando ggplot().

Atención

La visualización de datos es parte arte y parte ciencia y, como bien dice Claus Wilke, el desafío es realizar correctamente el arte sin desfigurar la ciencia (y viceversa).

Hay tres razones centrales por las que visualizamos la información:

  • Explorar los datos: hay relaciones que podemos malinterpretar si sólo miramos métricas resumen.

  • Expresar relaciones complejas: no siempre las tablas nos van a permitir ver con claridad cuando hay mucha información involucrada.

  • Comunicar: en general, construimos información para contársela a otras personas. Probablemente sea más fácil de contar una historia con un gráfico que con una tabla, por ejemplo.

La librería estrella de la visualización en Tidyverse funciona a través de capas. Cada una se corresponde con funciones diferentes dentro de la visualización.

Code
data %>% 
  filter(Partido=="LA LIBERTAD AVANZA") %>% 
  mutate(Porcentaje = as.numeric(Porcentaje)) %>% 
  ggplot(aes(y=id, x=Porcentaje)) + # con ggplot se asigna un lienzo en blanco, con aes se asignan variables a elementos de los gráficos
  geom_col() # definimos el gráfico a utilizar

Vamos a acomodar la parte estética.

Code
data %>% 
  filter(Partido=="LA LIBERTAD AVANZA") %>% 
  mutate(Porcentaje = as.numeric(Porcentaje),
         Porcentaje = round(Porcentaje,1)) %>% 
  ggplot(aes(y=reorder(id, Porcentaje), x=Porcentaje, fill=Porcentaje, label=Porcentaje)) + 
  geom_col(show.legend=FALSE)+
  geom_text(aes(x=Porcentaje+2), size=3) + 
  labs(x="", y="", 
       title="Votos de La Libertad Avanza (%) por provincia", 
       subtitle="Elecciones generales 2023", 
       caption="Elaboración propia según datos de datacp.ar")+
  theme_minimal()+
  scale_fill_distiller(palette = "Purples", direction = 1)

🧪 Práctica corta (15 minutos)

Elegir y resolver alguna de las siguientes consignas. De mayor a menor dificultad.

  • Graficar el porcentaje de voto a Unión por la Patria por provincia (considerar la coherencia con la paleta de colores).
  • Graficar los votos absolutos a La Libertad Avanza por provincia.
  • Graficar la suma entre el voto a La Libertad Avanza y Juntos por el Cambio, pensando en la alianza posterior en el balotaje.

1.6. Información geográfica

Hay distintos formatos para los archivos geográficos. Los más conocidos son Shapefile (compuesto por varios archivos con distintos atributos) y GeoJSON (archivo de texto). Lo particular de este tipo de archivos es la columna de geometry.

Cargamos librería sf.

Code
library(sf)

Cargamos el archivo con información geográfica de las provincias. Al cargar se imprime la metadata.

Code
geo <- st_read(params$ruta_shp)
Reading layer `ign_provincia' from data source 
  `C:\Users\tomas.bustos\Documents\personal\estacion-r\mapas_en_accion\geo\ign_provincia\ign_provincia.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 24 features and 11 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -74 ymin: -90 xmax: -25 ymax: -21.78086
Geodetic CRS:  WGS 84

Vemos el tipo de objeto.

Code
geo %>% class() 
[1] "sf"         "data.frame"

Primeras filas.

Code
geo %>% head(3)
Simple feature collection with 3 features and 11 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -71.96569 ymin: -41.10059 xmax: -58.33515 ymax: -34.52653
Geodetic CRS:  WGS 84
  OBJECTID Entidad    Objeto                             FNA             GNA
1      427       0 Provincia Ciudad Autónoma de Buenos Aires Ciudad Autónoma
2      428       0 Provincia           Provincia del Neuquén       Provincia
3      429       0 Provincia           Provincia de La Pampa       Provincia
                              NAM SAG       FDC IN1  SHAPE_STAr SHAPE_STLe
1 Ciudad Autónoma de Buenos Aires IGN Geografía  02  0.02024179  0.7438065
2                         Neuquén IGN Geografía  58  9.77181088 21.5159846
3                        La Pampa IGN Geografía  42 14.55301930 19.6656145
                        geometry
1 MULTIPOLYGON (((-58.34189 -...
2 MULTIPOLYGON (((-70.39345 -...
3 MULTIPOLYGON (((-64.76547 -...

La misma librería ggplot nos permite graficar archivos geográficos.

Code
geo %>%
  ggplot() +
  geom_sf()

El sistema de coordenadas de referencia (CRS por sus siglas en inglés) es la traducción entre los rasgos geográficos presentes en la superficie tridimensional esférica (la Tierra) y el plano donde mostramos la información geográfica. El más conocido es latitud y longitud (como se ve en el gráfico de arriba). Para poder trabajar con distintos archivos geográficos deberíamos tenerlos todos en un mismo sistema de coordenadas.

Code
geo %>% st_crs()
Coordinate Reference System:
  User input: WGS 84 
  wkt:
GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["latitude",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["longitude",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    ID["EPSG",4326]]

Se podrían transformar las coordenadas geográficas.

Hay tres tipos principales de objetos geográficos. Puntos (conjunto de coordenadas), líneas (conjunto de puntos) y polígonos (conjunto de líneas conectadas que forman un objeto cerrado). Carguemos archivos de esos tipos para poder verlos en el mapa.

Code
ruta_puntos <- "https://wms.ign.gob.ar/geoserver/ign/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ign%3Agobiernoslocales_2022&outputFormat=application%2Fjson"
geo_goblocales <- st_read(ruta_puntos, quiet=TRUE)
geo_goblocales %>% head(5)
Simple feature collection with 5 features and 13 fields
Geometry type: MULTIPOINT
Dimension:     XY
Bounding box:  xmin: -65.16929 ymin: -36.6739 xmax: -59.26195 ymax: -28.14589
Geodetic CRS:  WGS 84
                          id  gid         objeto             fna       gna
1 gobiernoslocales_2022.1218 1218 Gobierno local Comuna La Pampa    Comuna
2 gobiernoslocales_2022.1624 1624 Gobierno local  Municipio Toay Municipio
3    gobiernoslocales_2022.1    1 Gobierno local  Comuna Talaini    Comuna
4    gobiernoslocales_2022.2    2 Gobierno local    Comuna Silva    Comuna
5    gobiernoslocales_2022.3    3 Gobierno local    Comuna Hardy    Comuna
       nam    in1       tgl cod_tgl nam_prov cod_prov   fdc sag
1 La Pampa 143183    Comuna      CO  Córdoba       14 BAHRA IGN
2     Toay 420357 Municipio      MU La Pampa       42 BAHRA IGN
3  Talaini 142392    Comuna      CO  Córdoba       14 BAHRA IGN
4    Silva 823960    Comuna      CO Santa Fe       82 BAHRA IGN
5    Hardy 822808    Comuna      CO Santa Fe       82 BAHRA IGN
                        geometry
1 MULTIPOINT ((-64.27694 -30....
2 MULTIPOINT ((-64.37979 -36....
3 MULTIPOINT ((-65.16929 -31....
4 MULTIPOINT ((-60.43056 -30....
5 MULTIPOINT ((-59.26195 -28....
Code
ruta_lineas <- "https://wms.ign.gob.ar/geoserver/ign/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ign%3Alinea_de_limite_070114&outputFormat=application%2Fjson"
geo_areasprotegidas <- st_read(ruta_lineas, quiet=TRUE)
geo_areasprotegidas %>% head(5)
Simple feature collection with 5 features and 6 fields
Geometry type: MULTILINESTRING
Dimension:     XY
Bounding box:  xmin: -70.67351 ymin: -54.50302 xmax: -59.48689 ymax: -30.33253
Geodetic CRS:  WGS 84
                            id   gid entidad                   objeto   fdc
1 linea_de_limite_070114.31476 31476      13 Límite de área protegida  <NA>
2 linea_de_limite_070114.31477 31477      13 Límite de área protegida  <NA>
3 linea_de_limite_070114.24699 24699      13 Límite de área protegida  <NA>
4 linea_de_limite_070114.24700 24700      13 Límite de área protegida MAyDS
5 linea_de_limite_070114.24701 24701      13 Límite de área protegida MAyDS
   sag                       geometry
1  IGN MULTILINESTRING ((-59.54657...
2  IGN MULTILINESTRING ((-60.65683...
3 <NA> MULTILINESTRING ((-70.4166 ...
4  IGN MULTILINESTRING ((-68.60859...
5  IGN MULTILINESTRING ((-68.60844...

Veamoslo gráficamente.

Code
ggplot() +
  geom_sf(data = geo, aes(color = "Provincias")) +
  geom_sf(data = geo_goblocales, aes(color = "Gobiernos locales"), alpha = .1) +
  geom_sf(data = geo_areasprotegidas, aes(color = "Áreas protegidas")) +
  coord_sf(
    xlim = c(-75, -52),  # longitudes aprox de Argentina continental
    ylim = c(-58, -20),  # latitudes aprox de Argentina continental
    expand = FALSE
  ) +
  scale_color_manual(
    name = "Capas",  
    values = c(
      "Provincias" = "black",
      "Gobiernos locales" = "blue",
      "Áreas protegidas" = "red"
    )
  ) +
  theme_void()

Volviendo al mundo electoral. Una vez que tenemos la información geográfica y los datos que queremos graficar, necesitamos unir ambos objetos. Para ello, necesitaremos una clave, esto es, una variable que sea igual en ambas tablas como para realizar la unión.

Code
data %>% distinct(id) %>% arrange(id) %>% as.vector() %>% print()
$id
 [1] "BUENOS AIRES"                    "CATAMARCA"                      
 [3] "CHACO"                           "CHUBUT"                         
 [5] "CIUDAD AUTONOMA DE BUENOS AIRES" "CORDOBA"                        
 [7] "CORRIENTES"                      "ENTRE RIOS"                     
 [9] "FORMOSA"                         "JUJUY"                          
[11] "LA PAMPA"                        "LA RIOJA"                       
[13] "MENDOZA"                         "MISIONES"                       
[15] "NEUQUEN"                         "RIO NEGRO"                      
[17] "SALTA"                           "SAN JUAN"                       
[19] "SAN LUIS"                        "SANTA CRUZ"                     
[21] "SANTA FE"                        "SANTIAGO DEL ESTERO"            
[23] "TIERRA DEL FUEGO"                "TUCUMAN"                        
Code
geo %>% st_drop_geometry() %>% distinct(NAM) %>% arrange(NAM) %>% as.vector() %>% print()
$NAM
 [1] "Buenos Aires"                                         
 [2] "Catamarca"                                            
 [3] "Chaco"                                                
 [4] "Chubut"                                               
 [5] "Ciudad Autónoma de Buenos Aires"                      
 [6] "Corrientes"                                           
 [7] "Córdoba"                                              
 [8] "Entre Ríos"                                           
 [9] "Formosa"                                              
[10] "Jujuy"                                                
[11] "La Pampa"                                             
[12] "La Rioja"                                             
[13] "Mendoza"                                              
[14] "Misiones"                                             
[15] "Neuquén"                                              
[16] "Río Negro"                                            
[17] "Salta"                                                
[18] "San Juan"                                             
[19] "San Luis"                                             
[20] "Santa Cruz"                                           
[21] "Santa Fe"                                             
[22] "Santiago del Estero"                                  
[23] "Tierra del Fuego, Antártida e Islas del Atlántico Sur"
[24] "Tucumán"                                              

Vamos a transformar los textos para que coincidan entre sí.

Code
geo <- geo %>% 
  mutate(key = str_to_upper(NAM), 
         key = stringi::stri_trans_general(key, "Latin-ASCII"), 
         key = str_replace(key, ", ANTARTIDA E ISLAS DEL ATLANTICO SUR", "")) %>% 
  select(key, geometry)

geo %>% st_drop_geometry() %>% distinct(key) %>% arrange(key) %>% as.vector() %>% print()
$key
 [1] "BUENOS AIRES"                    "CATAMARCA"                      
 [3] "CHACO"                           "CHUBUT"                         
 [5] "CIUDAD AUTONOMA DE BUENOS AIRES" "CORDOBA"                        
 [7] "CORRIENTES"                      "ENTRE RIOS"                     
 [9] "FORMOSA"                         "JUJUY"                          
[11] "LA PAMPA"                        "LA RIOJA"                       
[13] "MENDOZA"                         "MISIONES"                       
[15] "NEUQUEN"                         "RIO NEGRO"                      
[17] "SALTA"                           "SAN JUAN"                       
[19] "SAN LUIS"                        "SANTA CRUZ"                     
[21] "SANTA FE"                        "SANTIAGO DEL ESTERO"            
[23] "TIERRA DEL FUEGO"                "TUCUMAN"                        
Code
joined <- data %>% 
  filter(Partido == "LA LIBERTAD AVANZA") %>% 
  mutate(key = id,
         Porcentaje = as.numeric(Porcentaje), 
         label = round(Porcentaje)) %>% 
  select(key, Porcentaje, label) %>% 
  left_join(geo) %>% 
  st_as_sf()

joined %>% head()
Simple feature collection with 6 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -72.18826 ymin: -45.99979 xmax: -56.66499 ymax: -24.0844
Geodetic CRS:  WGS 84
# A tibble: 6 × 4
  key                             Porcentaje label                      geometry
  <chr>                                <dbl> <dbl>            <MULTIPOLYGON [°]>
1 BUENOS AIRES                          25.7    26 (((-60.27237 -33.26349, -60.…
2 CATAMARCA                             32.0    32 (((-68.10862 -25.21178, -68.…
3 CHACO                                 27.8    28 (((-62.24919 -24.14075, -62.…
4 CHUBUT                                35.0    35 (((-66.69852 -45.24747, -66.…
5 CIUDAD AUTONOMA DE BUENOS AIRES       19.8    20 (((-58.34189 -34.6311, -58.3…
6 CORDOBA                               33.6    34 (((-63.87035 -29.62387, -63.…

Finalmente graficamos el resultado de La Libertad Avanza por provincia en un mapa de la Argentina.

Code
joined %>% 
  ggplot()+
  geom_sf(aes(fill=Porcentaje)) +
  coord_sf(
    xlim = c(-75, -52),  # longitudes aprox de Argentina continental
    ylim = c(-58, -20),  # latitudes aprox de Argentina continental
    expand = FALSE
  ) +
  scale_fill_distiller(palette = "Purples", direction = 1) + 
  labs(x="", y="", fill="%",
       title="La Libertad Avanza", 
       subtitle="Votos en las elecciones generales 2023", 
       caption="Elaboración propia según datos de datacp.ar")+
  theme_void()


🧩 Para seguir practicando

  • Hacer un mapa con resultados de otra fuerza.
  • Hacer un mapa graficando la participación.
  • Hacer un mapa de resultados tomando sólo de la Patagonia argentina.

————————————————————————

Mapas en acción: Análisis y visualización espacial con R

El objetivo del curso es adquirir herramientas para la visualización de información geográfica utilizando R en el ámbito de las Ciencias Sociales. Se utilizarán datos electorales como un ejemplo concreto y cercano, un hilo temático que le dará estructura, coherencia e integridad a los encuentros. Habrá contenidos de tres tipos: manejo de datos, herramientas de visualización y un ejemplo concreto donde lo anterior esté aplicado. La idea es ir avanzando de manera iterativa, pasando en todas los encuentros por los tres tipos de contenidos mencionados antes e ir complejizando su utilziación a medida que avanzan los encuentros.

Como herramienta didáctica, cada encuentro tendrá una pregunta que nos guíe. Es importante para evitar perdernos en el mar de información disponible. Enfocar los esfuerzos nos va a ayudar a buscar mejor qué función necesitamos para responder nuestra pregunta y además valoriza uno de los elementos más importantes que tienen para aportar las Ciencias Sociales al mundo de datos: hacer preguntas interesantes.

1. Calentando motores

La idea de este encuentro es repasar manejo de datos con tidyverse, conocer objetos geográficos mínimos con sf y hacer una pequeña introducción a visualización con ggplot.

Librerías necesarias: tidyverse, sf.

1.1. Antes de arrancar: conociendo los utensilios

Un breve y necesario paréntesis de definiciones de los elementos con los que vamos a estar trabajando.

  • Script: secuencia de comandos. Nuestros scripts estarán escritos en R.

  • Rstudio: plataforma que usaremos para administrar los archivos necesarios para trabajar con R.

  • Proyecto de Rstudio: es una forma de agrupar los distintos scripts y archivos que utilicemos en un sólo lugar. También nos facilita trabajar con directorios o guardar ciertas configuraciones del entorno.

  • Documento de R (.r): archivo con instrucciones escritas en R.

  • Documento de RMarkdown (.rmd): archivo que permite combinar instrucciones escritas en R con distintos formatos de texto. Se utiliza para escribir informes fáciles para leer y cómodos para trabajar.

  • Quarto document (.qmd): Símil al anterior, pero permite distintos lenguajes. Es el que está presente en la mayor parte de este curso.

  • Función: conjunto de instrucciones empaquetados para usar con mayor comodidad.

  • Paquete/Librerías: conjunto de funciones, en general, con el objetivo de trabajar en un rubro en particular o con cierto tipo de datos.

1.2. Pregunta-problema

Por ser el primer encuentro vamos a empezar por una pregunta sencilla. ¿Cómo fue el porcentaje de votos de La Libertad Avanza en las provincias argentinas en las elecciones presidenciales generales de 2023?

1.3. Introducción a toda marcha

Lo primero y principal es cargar las librerías que vamos a utilizar para responder a nuestra pregunta-problema. Aquí le damos la bienvenida a tidyverse: un conjunto de paquetes quetienen una manera similar de escribirse y utilizarse, facilitando el trabajo conjunto de las distintas librerías. La primera vez que se utiliza una librería, hay que descargarla con la función install.packages().

Code
#install.packages("tidyverse") # instalamos el conjunto de librerías que componen la colección tidyverse
#install.packages("sf") # instalamos la librería que usaremos para operaciones con información geográfica

Una vez instalados los paquetes se cargan en la instancia de trabajo que estamos utilizando.

Code
library(tidyverse)
library(sf)

Luego, tenemos que cargar los datos que vamos a utilizar. La función dependerá del tipo de archivo que tengamos que cargar. Los tipos de archivos más comunes son .csv y .xlsx. Los datos están descargados de la plataforma Data CP. Si hay problemas con la ruta, pueden saber dónde está ubicado R con la función getwd().

Cuando utilizamos R vamos a estar utilizando objetos. El operador <- se utiliza para asignar el resultado de una función a un objeto y se puede crear con botón alt + botón -. Los objetos pertenecen a una clase, lo que implica que se permiten ciertas operaciones y se restringen otras. Por ejemplo, a los números se les puede aplicar operaciones aritméticas, a las tablas se les puede consultar sus filas-columnas y a las cadenas de texto se las puede pasar a mayúsculas.

Code
class(data)
[1] "tbl_df"     "tbl"        "data.frame"

A los archivos del tipo data.frame podemos aplicarle distintas funciones para hacer una exploración rápida de qué hay dentro. dim devuelve filas y columnas:

Code
dim(data)
[1] 192   8

glipmse() devuelve nombres de columnas, tipos de datos, valores de ejemplo:

Code
glimpse(data)
Rows: 192
Columns: 8
$ id            <chr> "BUENOS AIRES", "CATAMARCA", "CHACO", "CHUBUT", "CIUDAD …
$ Elecciones    <chr> "GENERALES 2023", "GENERALES 2023", "GENERALES 2023", "G…
$ Partido       <chr> "BLANCO", "BLANCO", "BLANCO", "BLANCO", "BLANCO", "BLANC…
$ Porcentaje    <chr> "2.64", "5.16", "1.1", "1.27", "1.69", "0.77", "1.1", "4…
$ Votos         <chr> "269648", "12804", "7960", "4502", "32311", "17852", "78…
$ Participacion <chr> "77.71", "72.81", "72.45", "74.54", "75.65", "76.19", "7…
$ Electores     <chr> "13124435", "340606", "1000094", "474701", "2526676", "3…
$ Votantes      <chr> "10199399", "247986", "724566", "353825", "1911431", "23…

Para seleccionar filas que nos interesan, según algún valor, podemos utilizar la función filter().

Code
data %>% 
  filter(Partido=="LA LIBERTAD AVANZA" & Porcentaje > 40)
# A tibble: 4 × 8
  id       Elecciones  Partido Porcentaje Votos Participacion Electores Votantes
  <chr>    <chr>       <chr>   <chr>      <chr> <chr>         <chr>     <chr>   
1 MENDOZA  GENERALES … LA LIB… 42.36      4693… 76.45         1494888   1142804 
2 MISIONES GENERALES … LA LIB… 42.13      3056… 75.89         989204    750671  
3 SALTA    GENERALES … LA LIB… 40.4       3091… 71.66         1091792   782342  
4 SAN LUIS GENERALES … LA LIB… 43.37      1382… 77.99         421037    328355  

Con el operador pipe (%>%) se concatenan las distintas funciones. Si en cambio queremos seleccionar algunas columnas, la función select() es la indicada:

Code
data %>% 
  filter(Partido=="LA LIBERTAD AVANZA") %>% 
  select(id, Porcentaje)
# A tibble: 24 × 2
   id                              Porcentaje
   <chr>                           <chr>     
 1 BUENOS AIRES                    25.72     
 2 CATAMARCA                       32.04     
 3 CHACO                           27.77     
 4 CHUBUT                          35.02     
 5 CIUDAD AUTONOMA DE BUENOS AIRES 19.85     
 6 CORDOBA                         33.55     
 7 CORRIENTES                      26.89     
 8 ENTRE RIOS                      29.75     
 9 FORMOSA                         29.04     
10 JUJUY                           37.39     
# ℹ 14 more rows

Limpiar y transformar una base de datos es un proceso creativo que implica adaptar las variables según el uso que se le va a dar. Se dice creativo porque, si bien hay ciertas funciones y procesos frecuentes, varía mucho según cada proyecto y origen de la base. mutate() es una de las funciones más importantes para este momento.

Code
data %>% 
  mutate(provincia_minusc = str_to_lower(id),
         participacion_v2 = as.numeric(Votantes) / as.numeric(Electores) * 100) %>% 
  select(id, provincia_minusc, Participacion, participacion_v2)
# A tibble: 192 × 4
   id                            provincia_minusc Participacion participacion_v2
   <chr>                         <chr>            <chr>                    <dbl>
 1 BUENOS AIRES                  buenos aires     77.71                     77.7
 2 CATAMARCA                     catamarca        72.81                     72.8
 3 CHACO                         chaco            72.45                     72.4
 4 CHUBUT                        chubut           74.54                     74.5
 5 CIUDAD AUTONOMA DE BUENOS AI… ciudad autonoma… 75.65                     75.7
 6 CORDOBA                       cordoba          76.19                     76.2
 7 CORRIENTES                    corrientes       76.8                      76.8
 8 ENTRE RIOS                    entre rios       76.8                      76.8
 9 FORMOSA                       formosa          75.61                     75.6
10 JUJUY                         jujuy            78.35                     78.4
# ℹ 182 more rows

A veces es necesario hacer cálculos de agrupamiento en nuestras tablas. Las funciones group_by() y summarise() pueden funcionar. Por ejemplo, calculemos el promedio de cada partido en las distintas provincias:

Code
data %>% 
  select(Partido, Porcentaje) %>% 
  mutate(Porcentaje = as.numeric(Porcentaje)) %>% 
  group_by(Partido) %>% 
  summarise(mean = mean(Porcentaje)) %>% 
  arrange(desc(mean)) %>% 
  mutate(mean = round(mean, 2))
# A tibble: 8 × 2
  Partido                                         mean
  <chr>                                          <dbl>
1 UNION POR LA PATRIA                            36.8 
2 LA LIBERTAD AVANZA                             33.4 
3 JUNTOS POR EL CAMBIO                           20.8 
4 HACEMOS POR NUESTRO PAIS                        6.55
5 FRENTE DE IZQUIERDA Y DE TRABAJADORES - UNIDAD  2.37
6 BLANCO                                          2.04
7 NULO                                            0.99
8 IMPUGNADO                                       0.11

Tip: mantené los nombres de variables simples, sin espacios y con mayúsculas/minúsculas consistentes.

1.4. Formatos

La mayor particularidad de los resultados electorales es tener formato long (largo). En el formato long, cada fila de la tabla representa una observación única para una combinación específica de variables. Es útil para trabajar con datos que necesitan ser agrupados o resumidos fácilmente. Cada variable está dividida en dos columnas: una para el nombre de la variable y otra para su valor. El formato alternativo es wide, donde cada fila representa una observación única y cada columna representa una variable diferente. Es útil cuando se necesita acceder rápidamente a las variables individuales sin necesidad de realizar transformaciones adicionales.

formatos de tabla

Quizás sea más cómodo alternar entre formato long y wide. Para aquellos casos, pivot_longer() y pivot_wider() nos van a servir.

Las bases electorales suelen venir en formato long. Para la lectura, suele ser más cómodo el formato wide.

Code
data_wider <- data %>%
  select(id, Partido, Porcentaje) %>% 
  pivot_wider(names_from=Partido, values_from=Porcentaje)
data_wider
# A tibble: 24 × 9
   id             BLANCO FRENTE DE IZQUIERDA …¹ HACEMOS POR NUESTRO …² IMPUGNADO
   <chr>          <chr>  <chr>                  <chr>                  <chr>    
 1 BUENOS AIRES   2.64   3.58                   3.73                   0.13     
 2 CATAMARCA      5.16   1.57                   6.43                   0.26     
 3 CHACO          1.1    0.77                   3.63                   0.16     
 4 CHUBUT         1.27   4.4                    7.73                   0.11     
 5 CIUDAD AUTONO… 1.69   3.55                   3.09                   0.12     
 6 CORDOBA        0.77   1.39                   29.01                  0.03     
 7 CORRIENTES     1.1    1.05                   2.74                   0.12     
 8 ENTRE RIOS     4.25   1.53                   5.37                   0.16     
 9 FORMOSA        1.28   0.77                   2.46                   0.07     
10 JUJUY          1.35   3.54                   6.81                   0.07     
# ℹ 14 more rows
# ℹ abbreviated names: ¹​`FRENTE DE IZQUIERDA Y DE TRABAJADORES - UNIDAD`,
#   ²​`HACEMOS POR NUESTRO PAIS`
# ℹ 4 more variables: `JUNTOS POR EL CAMBIO` <chr>, `LA LIBERTAD AVANZA` <chr>,
#   NULO <chr>, `UNION POR LA PATRIA` <chr>

Si quisiéramos volver al formato anterior:

Code
data_wider %>% 
  pivot_longer(!id, values_to="valor")
# A tibble: 192 × 3
   id           name                                           valor
   <chr>        <chr>                                          <chr>
 1 BUENOS AIRES BLANCO                                         2.64 
 2 BUENOS AIRES FRENTE DE IZQUIERDA Y DE TRABAJADORES - UNIDAD 3.58 
 3 BUENOS AIRES HACEMOS POR NUESTRO PAIS                       3.73 
 4 BUENOS AIRES IMPUGNADO                                      0.13 
 5 BUENOS AIRES JUNTOS POR EL CAMBIO                           24.1 
 6 BUENOS AIRES LA LIBERTAD AVANZA                             25.72
 7 BUENOS AIRES NULO                                           0.63 
 8 BUENOS AIRES UNION POR LA PATRIA                            42.88
 9 CATAMARCA    BLANCO                                         5.16 
10 CATAMARCA    FRENTE DE IZQUIERDA Y DE TRABAJADORES - UNIDAD 1.57 
# ℹ 182 more rows

1.5. Visualización

En este apartado nos enfocaremos en entender por qué visualizar datos y cómo construirlos utilizando ggplot().

Atención

La visualización de datos es parte arte y parte ciencia y, como bien dice Claus Wilke, el desafío es realizar correctamente el arte sin desfigurar la ciencia (y viceversa).

Hay tres razones centrales por las que visualizamos la información:

  • Explorar los datos: hay relaciones que podemos malinterpretar si sólo miramos métricas resumen.

  • Expresar relaciones complejas: no siempre las tablas nos van a permitir ver con claridad cuando hay mucha información involucrada.

  • Comunicar: en general, construimos información para contársela a otras personas. Probablemente sea más fácil de contar una historia con un gráfico que con una tabla, por ejemplo.

La librería estrella de la visualización en Tidyverse funciona a través de capas. Cada una se corresponde con funciones diferentes dentro de la visualización.

Code
data %>% 
  filter(Partido=="LA LIBERTAD AVANZA") %>% 
  mutate(Porcentaje = as.numeric(Porcentaje)) %>% 
  ggplot(aes(y=id, x=Porcentaje)) + # con ggplot se asigna un lienzo en blanco, con aes se asignan variables a elementos de los gráficos
  geom_col() # definimos el gráfico a utilizar

Vamos a acomodar la parte estética.

Code
data %>% 
  filter(Partido=="LA LIBERTAD AVANZA") %>% 
  mutate(Porcentaje = as.numeric(Porcentaje),
         Porcentaje = round(Porcentaje,1)) %>% 
  ggplot(aes(y=reorder(id, Porcentaje), x=Porcentaje, fill=Porcentaje, label=Porcentaje)) + 
  geom_col(show.legend=FALSE)+
  geom_text(aes(x=Porcentaje+2), size=3) + 
  labs(x="", y="", 
       title="Votos de La Libertad Avanza (%) por provincia", 
       subtitle="Elecciones generales 2023", 
       caption="Elaboración propia según datos de datacp.ar")+
  theme_minimal()+
  scale_fill_distiller(palette = "Purples", direction = 1)

🧪 Práctica corta (15 minutos)

Elegir y resolver alguna de las siguientes consignas. De mayor a menor dificultad.

  • Graficar el porcentaje de voto a Unión por la Patria por provincia (considerar la coherencia con la paleta de colores).
  • Graficar los votos absolutos a La Libertad Avanza por provincia.
  • Graficar la suma entre el voto a La Libertad Avanza y Juntos por el Cambio, pensando en la alianza posterior en el balotaje.

1.6. Información geográfica

Hay distintos formatos para los archivos geográficos. Los más conocidos son Shapefile (compuesto por varios archivos con distintos atributos) y GeoJSON (archivo de texto). Lo particular de este tipo de archivos es la columna de geometry.

Cargamos librería sf.

Code
library(sf)

Cargamos el archivo con información geográfica de las provincias. Al cargar se imprime la metadata.

Code
geo <- st_read(params$ruta_shp)
Reading layer `ign_provincia' from data source 
  `C:\Users\tomas.bustos\Documents\personal\estacion-r\mapas_en_accion\geo\ign_provincia\ign_provincia.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 24 features and 11 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -74 ymin: -90 xmax: -25 ymax: -21.78086
Geodetic CRS:  WGS 84

Vemos el tipo de objeto.

Code
geo %>% class() 
[1] "sf"         "data.frame"

Primeras filas.

Code
geo %>% head(3)
Simple feature collection with 3 features and 11 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -71.96569 ymin: -41.10059 xmax: -58.33515 ymax: -34.52653
Geodetic CRS:  WGS 84
  OBJECTID Entidad    Objeto                             FNA             GNA
1      427       0 Provincia Ciudad Autónoma de Buenos Aires Ciudad Autónoma
2      428       0 Provincia           Provincia del Neuquén       Provincia
3      429       0 Provincia           Provincia de La Pampa       Provincia
                              NAM SAG       FDC IN1  SHAPE_STAr SHAPE_STLe
1 Ciudad Autónoma de Buenos Aires IGN Geografía  02  0.02024179  0.7438065
2                         Neuquén IGN Geografía  58  9.77181088 21.5159846
3                        La Pampa IGN Geografía  42 14.55301930 19.6656145
                        geometry
1 MULTIPOLYGON (((-58.34189 -...
2 MULTIPOLYGON (((-70.39345 -...
3 MULTIPOLYGON (((-64.76547 -...

La misma librería ggplot nos permite graficar archivos geográficos.

Code
geo %>%
  ggplot() +
  geom_sf()

Trabajar con mapas implica representar un elemento tridimensional (la Tierra) en un elemento bidimensional (un plano). Para eso se utilizan proyecciones cartográficas.

El sistema de coordenadas de referencia (CRS por sus siglas en inglés) se utiliza para definir la ubicación de los diferentes elementos. El más conocido es latitud y longitud (como se ve en el gráfico de arriba). Para poder trabajar con distintos archivos geográficos deberíamos tenerlos todos en un mismo sistema de coordenadas.

Code
geo %>% st_crs()
Coordinate Reference System:
  User input: WGS 84 
  wkt:
GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["latitude",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["longitude",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    ID["EPSG",4326]]

Un ejemplo. Cada proyección distorsiona algún elemento (la forma, la distancia, el área). Mercator deforma lo que está más cerca de los polos.

Lo importante es que todos nuestros objetos estén en el mismo sistema de coordenadas. Se pueden transformar.

Hay tres tipos principales de objetos geográficos. Puntos (conjunto de coordenadas), líneas (conjunto de puntos) y polígonos (conjunto de líneas conectadas que forman un objeto cerrado). Carguemos archivos de esos tipos para poder verlos en el mapa.

Code
ruta_puntos <- "https://wms.ign.gob.ar/geoserver/ign/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ign%3Agobiernoslocales_2022&outputFormat=application%2Fjson"
geo_goblocales <- st_read(ruta_puntos, quiet=TRUE)
geo_goblocales %>% head(5)
Simple feature collection with 5 features and 13 fields
Geometry type: MULTIPOINT
Dimension:     XY
Bounding box:  xmin: -65.16929 ymin: -36.6739 xmax: -59.26195 ymax: -28.14589
Geodetic CRS:  WGS 84
                          id  gid         objeto             fna       gna
1 gobiernoslocales_2022.1218 1218 Gobierno local Comuna La Pampa    Comuna
2 gobiernoslocales_2022.1624 1624 Gobierno local  Municipio Toay Municipio
3    gobiernoslocales_2022.1    1 Gobierno local  Comuna Talaini    Comuna
4    gobiernoslocales_2022.2    2 Gobierno local    Comuna Silva    Comuna
5    gobiernoslocales_2022.3    3 Gobierno local    Comuna Hardy    Comuna
       nam    in1       tgl cod_tgl nam_prov cod_prov   fdc sag
1 La Pampa 143183    Comuna      CO  Córdoba       14 BAHRA IGN
2     Toay 420357 Municipio      MU La Pampa       42 BAHRA IGN
3  Talaini 142392    Comuna      CO  Córdoba       14 BAHRA IGN
4    Silva 823960    Comuna      CO Santa Fe       82 BAHRA IGN
5    Hardy 822808    Comuna      CO Santa Fe       82 BAHRA IGN
                        geometry
1 MULTIPOINT ((-64.27694 -30....
2 MULTIPOINT ((-64.37979 -36....
3 MULTIPOINT ((-65.16929 -31....
4 MULTIPOINT ((-60.43056 -30....
5 MULTIPOINT ((-59.26195 -28....
Code
ruta_lineas <- "https://wms.ign.gob.ar/geoserver/ign/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ign%3Alinea_de_limite_070114&outputFormat=application%2Fjson"
geo_areasprotegidas <- st_read(ruta_lineas, quiet=TRUE)
geo_areasprotegidas %>% head(5)
Simple feature collection with 5 features and 6 fields
Geometry type: MULTILINESTRING
Dimension:     XY
Bounding box:  xmin: -70.67351 ymin: -54.50302 xmax: -59.48689 ymax: -30.33253
Geodetic CRS:  WGS 84
                            id   gid entidad                   objeto   fdc
1 linea_de_limite_070114.31476 31476      13 Límite de área protegida  <NA>
2 linea_de_limite_070114.31477 31477      13 Límite de área protegida  <NA>
3 linea_de_limite_070114.24699 24699      13 Límite de área protegida  <NA>
4 linea_de_limite_070114.24700 24700      13 Límite de área protegida MAyDS
5 linea_de_limite_070114.24701 24701      13 Límite de área protegida MAyDS
   sag                       geometry
1  IGN MULTILINESTRING ((-59.54657...
2  IGN MULTILINESTRING ((-60.65683...
3 <NA> MULTILINESTRING ((-70.4166 ...
4  IGN MULTILINESTRING ((-68.60859...
5  IGN MULTILINESTRING ((-68.60844...

Veamoslo gráficamente.

Code
ggplot() +
  geom_sf(data = geo, aes(color = "Provincias")) +
  geom_sf(data = geo_goblocales, aes(color = "Gobiernos locales"), alpha = .1) +
  geom_sf(data = geo_areasprotegidas, aes(color = "Áreas protegidas")) +
  coord_sf(
    xlim = c(-75, -52),  # longitudes aprox de Argentina continental
    ylim = c(-58, -20),  # latitudes aprox de Argentina continental
    expand = FALSE
  ) +
  scale_color_manual(
    name = "Capas",  
    values = c(
      "Provincias" = "black",
      "Gobiernos locales" = "blue",
      "Áreas protegidas" = "red"
    )
  ) +
  theme_void()

Volviendo al mundo electoral. Una vez que tenemos la información geográfica y los datos que queremos graficar, necesitamos unir ambos objetos. Para ello, necesitaremos una clave, esto es, una variable que sea igual en ambas tablas como para realizar la unión.

Code
data %>% distinct(id) %>% arrange(id) %>% as.vector() %>% print()
$id
 [1] "BUENOS AIRES"                    "CATAMARCA"                      
 [3] "CHACO"                           "CHUBUT"                         
 [5] "CIUDAD AUTONOMA DE BUENOS AIRES" "CORDOBA"                        
 [7] "CORRIENTES"                      "ENTRE RIOS"                     
 [9] "FORMOSA"                         "JUJUY"                          
[11] "LA PAMPA"                        "LA RIOJA"                       
[13] "MENDOZA"                         "MISIONES"                       
[15] "NEUQUEN"                         "RIO NEGRO"                      
[17] "SALTA"                           "SAN JUAN"                       
[19] "SAN LUIS"                        "SANTA CRUZ"                     
[21] "SANTA FE"                        "SANTIAGO DEL ESTERO"            
[23] "TIERRA DEL FUEGO"                "TUCUMAN"                        
Code
geo %>% st_drop_geometry() %>% distinct(NAM) %>% arrange(NAM) %>% as.vector() %>% print()
$NAM
 [1] "Buenos Aires"                                         
 [2] "Catamarca"                                            
 [3] "Chaco"                                                
 [4] "Chubut"                                               
 [5] "Ciudad Autónoma de Buenos Aires"                      
 [6] "Corrientes"                                           
 [7] "Córdoba"                                              
 [8] "Entre Ríos"                                           
 [9] "Formosa"                                              
[10] "Jujuy"                                                
[11] "La Pampa"                                             
[12] "La Rioja"                                             
[13] "Mendoza"                                              
[14] "Misiones"                                             
[15] "Neuquén"                                              
[16] "Río Negro"                                            
[17] "Salta"                                                
[18] "San Juan"                                             
[19] "San Luis"                                             
[20] "Santa Cruz"                                           
[21] "Santa Fe"                                             
[22] "Santiago del Estero"                                  
[23] "Tierra del Fuego, Antártida e Islas del Atlántico Sur"
[24] "Tucumán"                                              

Vamos a transformar los textos para que coincidan entre sí.

Code
geo <- geo %>% 
  mutate(key = str_to_upper(NAM), 
         key = stringi::stri_trans_general(key, "Latin-ASCII"), 
         key = str_replace(key, ", ANTARTIDA E ISLAS DEL ATLANTICO SUR", "")) %>% 
  select(key, geometry)

geo %>% st_drop_geometry() %>% distinct(key) %>% arrange(key) %>% as.vector() %>% print()
$key
 [1] "BUENOS AIRES"                    "CATAMARCA"                      
 [3] "CHACO"                           "CHUBUT"                         
 [5] "CIUDAD AUTONOMA DE BUENOS AIRES" "CORDOBA"                        
 [7] "CORRIENTES"                      "ENTRE RIOS"                     
 [9] "FORMOSA"                         "JUJUY"                          
[11] "LA PAMPA"                        "LA RIOJA"                       
[13] "MENDOZA"                         "MISIONES"                       
[15] "NEUQUEN"                         "RIO NEGRO"                      
[17] "SALTA"                           "SAN JUAN"                       
[19] "SAN LUIS"                        "SANTA CRUZ"                     
[21] "SANTA FE"                        "SANTIAGO DEL ESTERO"            
[23] "TIERRA DEL FUEGO"                "TUCUMAN"                        
Code
joined <- data %>% 
  filter(Partido == "LA LIBERTAD AVANZA") %>% 
  mutate(key = id,
         Porcentaje = as.numeric(Porcentaje), 
         label = round(Porcentaje)) %>% 
  select(key, Porcentaje, label) %>% 
  left_join(geo) %>% 
  st_as_sf()

joined %>% head()
Simple feature collection with 6 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -72.18826 ymin: -45.99979 xmax: -56.66499 ymax: -24.0844
Geodetic CRS:  WGS 84
# A tibble: 6 × 4
  key                             Porcentaje label                      geometry
  <chr>                                <dbl> <dbl>            <MULTIPOLYGON [°]>
1 BUENOS AIRES                          25.7    26 (((-60.27237 -33.26349, -60.…
2 CATAMARCA                             32.0    32 (((-68.10862 -25.21178, -68.…
3 CHACO                                 27.8    28 (((-62.24919 -24.14075, -62.…
4 CHUBUT                                35.0    35 (((-66.69852 -45.24747, -66.…
5 CIUDAD AUTONOMA DE BUENOS AIRES       19.8    20 (((-58.34189 -34.6311, -58.3…
6 CORDOBA                               33.6    34 (((-63.87035 -29.62387, -63.…

Finalmente graficamos el resultado de La Libertad Avanza por provincia en un mapa de la Argentina.

Code
joined %>% 
  ggplot()+
  geom_sf(aes(fill=Porcentaje)) +
  coord_sf(
    xlim = c(-75, -52),  # longitudes aprox de Argentina continental
    ylim = c(-58, -20),  # latitudes aprox de Argentina continental
    expand = FALSE
  ) +
  scale_fill_distiller(palette = "Purples", direction = 1) + 
  labs(x="", y="", fill="%",
       title="La Libertad Avanza", 
       subtitle="Votos en las elecciones generales 2023", 
       caption="Elaboración propia según datos de datacp.ar")+
  theme_void()


🧩 Para seguir practicando

  • Hacer un mapa con resultados de otra fuerza.
  • Hacer un mapa graficando la participación.
  • Hacer un mapa de resultados tomando sólo de la Patagonia argentina.